package com.ksyun.campus.metaserver.controller;

import com.ksyun.campus.metaserver.config.MinfsProperties;
import com.ksyun.campus.metaserver.domain.*;
import com.ksyun.campus.metaserver.domain.dto.*;
import com.ksyun.campus.metaserver.services.IFsckService;
import com.ksyun.campus.metaserver.services.IMetaService;
import com.ksyun.campus.metaserver.zk.ZooKeeperService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * MetaServer REST API Controller
 * 元数据服务REST API控制器，提供文件系统操作的HTTP接口
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/meta")
public class MetaController {
    
    /**
     * 元数据服务接口，提供核心文件系统操作
     */
    @Autowired
    private IMetaService metaService;
    
    /**
     * 文件系统检查服务接口，提供自动修复功能
     */
    @Autowired
    private IFsckService fsckService;
    
    /**
     * ZooKeeper服务，用于分布式协调
     */
    @Autowired
    private ZooKeeperService zooKeeperService;
    
    /**
     * MinFS配置属性
     */
    @Autowired
    private MinfsProperties properties;

    /**
     * 递归创建目录
     * 
     * @param request 创建目录请求，包含路径、权限、所有者和组信息
     * @return 创建的目录inode信息
     */
    @PostMapping("/mkdirs")
    public ApiResponse<Map<String, Object>> mkdirs(@Valid @RequestBody MkdirsRequest request) {
        try {
            // 调用元数据服务创建目录
            Inode inode = metaService.mkdirs(request.getPath(), request.getPermissions(), 
                    request.getOwner(), request.getGroup());
            
            // 返回成功响应，包含创建的inode信息
            return ApiResponse.success(Map.of("inode", inode));
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error creating directories: {}", request.getPath(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 创建文件接口
     * 
     * @param request 创建文件请求，包含路径、副本数、权限、所有者和组信息
     * @return 创建的文件ID和块大小
     */
    @PostMapping("/createFile")
    public ApiResponse<Map<String, Object>> createFile(@Valid @RequestBody CreateFileRequest request) {
        try {
            // 调用metaService的createFile方法，创建新文件，返回Inode对象
            Inode inode = metaService.createFile(request.getPath(), request.getReplication(),
                    request.getPermissions(), request.getOwner(), request.getGroup());
            
            // 构造成功响应，包含fileId和blockSize
            return ApiResponse.success(Map.of(
                    "fileId", inode.getFileId(),
                    "blockSize", properties.getCluster().getBlockSize()
            ));
        } catch (Exception e) {
            // 捕获异常，记录错误日志并返回错误响应
            log.error("Error creating file: {}", request.getPath(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 获取文件或目录状态信息
     * 
     * @param path 文件或目录路径
     * @return 文件或目录的状态信息
     */
    @GetMapping("/getStatus")
    public ApiResponse<StatInfo> getStatus(@RequestParam String path) {
        try {
            // 调用元数据服务获取状态信息
            StatInfo status = metaService.getStatus(path);
            return ApiResponse.success(status);
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error getting status for path: {}", path, e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 列出目录内容
     * 
     * @param path 目录路径
     * @return 目录中的文件和子目录列表
     */
    @GetMapping("/listStatus")
    public ApiResponse<Map<String, Object>> listStatus(@RequestParam String path) {
        try {
            // 调用元数据服务列出目录内容
            List<StatInfo> entries = metaService.listStatus(path);
            return ApiResponse.success(Map.of("entries", entries));
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error listing directory: {}", path, e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 删除文件或目录
     * 
     * @param request 删除请求，包含路径和是否递归删除的标志
     * @return 删除操作的结果
     */
    @DeleteMapping("/delete")
    public ApiResponse<Void> delete(@Valid @RequestBody DeleteRequest request) {
        try {
            // 调用元数据服务删除文件或目录
            metaService.delete(request.getPath(), request.isRecursive());
            return ApiResponse.success();
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error deleting: {}", request.getPath(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 打开文件进行读取或写入
     * 
     * @param request 打开文件请求，包含路径和打开模式（读或写）
     * @return 文件打开的结果，包含文件ID和块大小等信息
     */
    @PostMapping("/open")
    public ApiResponse<Map<String, Object>> open(@Valid @RequestBody OpenRequest request) {
        try {
            // 根据打开模式选择不同的处理方法
            if (request.getOpenMode() == OpenRequest.OpenMode.READ) {
                return openForRead(request.getPath());
            } else {
                return openForWrite(request.getPath());
            }
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error opening file: {}", request.getPath(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 为读取打开文件的内部方法
     * 
     * @param path 文件路径
     * @return 包含文件块信息的响应
     */
    private ApiResponse<Map<String, Object>> openForRead(String path) throws Exception {
        // 获取文件状态信息
        StatInfo status = metaService.getStatus(path);
        if (status.getType() != FileType.FILE) {
            return ApiResponse.error("Path is not a file: " + path);
        }
        
        // 通过路径解析获取文件的真实内部ID
        String fileId = metaService.resolvePathToFileId(path);
        
        // 获取文件的块信息
        List<BlockInfo> blocks = metaService.getFileBlocks(fileId);
        
        // 构造响应，包含文件ID、块大小和块信息
        return ApiResponse.success(Map.of(
                "fileId", fileId,
                "blockSize", properties.getCluster().getBlockSize(),
                "blocks", blocks
        ));
    }

    /**
     * 为写入打开文件的内部方法
     * 
     * @param path 文件路径
     * @return 包含文件ID和块大小的响应
     */
    private ApiResponse<Map<String, Object>> openForWrite(String path) throws Exception {
        // 获取文件状态信息
        StatInfo status = metaService.getStatus(path);
        if (status.getType() != FileType.FILE) {
            return ApiResponse.error("Path is not a file: " + path);
        }
        
        // 通过路径解析获取文件的真实内部ID
        String fileId = metaService.resolvePathToFileId(path);
        
        // 构造响应，包含文件ID和块大小
        return ApiResponse.success(Map.of(
                "fileId", fileId,
                "blockSize", properties.getCluster().getBlockSize()
        ));
    }

    /**
     * 为文件分配写入块
     * 
     * @param request 分配块请求，包含文件ID和需要的字节数
     * @return 分配的块信息列表
     */
    @PostMapping("/allocateBlocks")
    public ApiResponse<Map<String, Object>> allocateBlocks(@Valid @RequestBody AllocateBlocksRequest request) {
        try {
            // 检查传入的是路径还是已经转换后的fileId
            String realFileId;
            if (request.getFileId().startsWith("/")) {
                // 是路径，需要解析为fileId
                realFileId = metaService.resolvePathToFileId(request.getFileId());
            } else {
                // 已经是fileId，直接使用
                realFileId = request.getFileId();
            }
            // 调用元数据服务分配块
            List<BlockInfo> blocks = metaService.allocateBlocks(realFileId, request.getBytes());
            return ApiResponse.success(Map.of("blocks", blocks));
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error allocating blocks for file: {}", request.getFileId(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 提交文件写入
     * 
     * @param request 提交请求，包含文件ID、大小、块信息和校验和
     * @return 提交操作的结果
     */
    @PostMapping("/commit")
    public ApiResponse<Void> commit(@Valid @RequestBody CommitRequest request) {
        try {
            // 检查传入的是路径还是已经转换后的fileId
            String realFileId;
            if (request.getFileId().startsWith("/")) {
                // 是路径，需要解析为fileId
                realFileId = metaService.resolvePathToFileId(request.getFileId());
            } else {
                // 已经是fileId，直接使用
                realFileId = request.getFileId();
            }
            
            // 将请求中的块信息转换为BlockInfo对象列表
            List<BlockInfo> blocks = request.getBlocks().stream().map(b ->
                    BlockInfo.builder()
                            .fileId(realFileId)
                            .blkIdx(b.getBlkIdx())
                            .size(b.getSize())
                            .build()
            ).collect(Collectors.toList());
            
            // 调用元数据服务提交写入
            metaService.commitWrite(realFileId, request.getSize(), blocks, request.getChecksum());
            return ApiResponse.success();
        } catch (Exception e) {
            // 记录错误日志并返回错误响应
            log.error("Error committing write for file: {}", request.getFileId(), e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 获取文件的块信息
     * 
     * @param fileId 文件ID或路径
     * @return 文件的块信息列表
     */
    @GetMapping("/getBlocks")
    public ApiResponse<Map<String, Object>> getBlocks(@RequestParam String fileId) {
        try {
            // 检查传入的是路径还是已经转换后的fileId
            String realFileId;
            if (fileId.startsWith("/")) {
                // 是路径，需要解析为fileId
                realFileId = metaService.resolvePathToFileId(fileId);
            } else {
                // 已经是fileId，直接使用
                realFileId = fileId;
            }
            
            // 获取文件的块信息
            List<BlockInfo> blocks = metaService.getFileBlocks(realFileId);
            
            return ApiResponse.success(Map.of(
                    "fileId", realFileId,
                    "totalBlocks", blocks.size(),
                    "blocks", blocks
            ));
        } catch (Exception e) {
            log.error("Error getting blocks for file: {}", fileId, e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 手动触发FSCK检查
     * 
     * @return FSCK执行结果统计
     */
    @PostMapping("/fsck")
    public ApiResponse<IFsckService.FsckStats> runFsck() {
        try {
            // 检查是否为Leader
            if (!zooKeeperService.isLeader()) {
                return ApiResponse.error("Only leader can run FSCK");
            }
            
            log.info("Manual FSCK triggered via API");
            IFsckService.FsckStats stats = fsckService.runFsck();
            return ApiResponse.success(stats);
        } catch (Exception e) {
            log.error("Error running FSCK", e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 获取最新的FSCK统计
     * 
     * @return 最新FSCK统计信息
     */
    @GetMapping("/fsck/stats")
    public ApiResponse<IFsckService.FsckStats> getFsckStats() {
        try {
            IFsckService.FsckStats stats = fsckService.getLatestFsckStats();
            if (stats == null) {
                // 如果没有统计信息，创建一个空的
                stats = new IFsckService.FsckStats();
            }
            return ApiResponse.success(stats);
        } catch (Exception e) {
            log.error("Error getting FSCK stats", e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 获取FSCK历史记录
     * 
     * @return FSCK历史记录列表
     */
    @GetMapping("/fsck/history")
    public ApiResponse<List<IFsckService.FsckStats>> getFsckHistory() {
        try {
            List<IFsckService.FsckStats> history = fsckService.getFsckHistory();
            return ApiResponse.success(history);
        } catch (Exception e) {
            log.error("Error getting FSCK history", e);
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 健康检查接口
     * 
     * @return 服务健康状态
     */
    @GetMapping("/health")
    public Map<String, Object> health() {
        Map<String, Object> status = new HashMap<>();
        status.put("status", "UP");
        status.put("isLeader", zooKeeperService.isLeader());
        status.put("timestamp", System.currentTimeMillis());
        status.put("version", "1.0");
        
        // 添加配置信息
        status.put("replicationFactor", properties.getCluster().getReplicationFactor());
        status.put("blockSize", properties.getCluster().getBlockSize());
        status.put("fsckEnabled", properties.getFsck().isEnabled());
        status.put("fsckInterval", properties.getFsck().getIntervalSeconds());
        
        return status;
    }

//    /**
//     * 兼容性旧接口 - 获取文件状态
//     */
//    @RequestMapping("/stats")
//    public ApiResponse<StatInfo> stats(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 调用新接口实现
//        return getStatus(path);
//    }
//
//    /**
//     * 兼容性旧接口 - 创建文件
//     */
//    @RequestMapping("/create")
//    public ApiResponse<Map<String, Object>> create(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 构造请求对象并调用新接口实现
//        CreateFileRequest request = CreateFileRequest.builder().path(path).build();
//        return createFile(request);
//    }
//

    //
//    /**
//     * 兼容性旧接口 - 创建目录
//     */
//    @RequestMapping("/mkdir")
//    public ApiResponse<Map<String, Object>> mkdir(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 构造请求对象并调用新接口实现
//        MkdirsRequest request = MkdirsRequest.builder().path(path).build();
//        return mkdirs(request);
//    }
//
//    /**
//     * 兼容性旧接口 - 列出目录
//     */
//    @RequestMapping("/listdir")
//    public ApiResponse<Map<String, Object>> listdir(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 调用新接口实现
//        return listStatus(path);
//    }
//
//    /**
//     * 兼容性旧接口 - 删除文件或目录
//     */
//    @RequestMapping("/delete")
//    public ApiResponse<Void> delete(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 构造请求对象并调用新接口实现
//        DeleteRequest request = DeleteRequest.builder().path(path).build();
//        return delete(request);
//    }
//
//    /**
//     * 兼容性旧接口 - 写入文件
//     * 此接口功能有限，建议使用新接口
//     */
//    @RequestMapping("/write")
//    public ApiResponse<Void> commitWrite(@RequestHeader(required = false) String fileSystemName,
//                                       @RequestParam String path,
//                                       @RequestParam int offset,
//                                       @RequestParam int length) {
//        // 返回错误提示，建议使用新接口
//        return ApiResponse.error("Use /api/v1/meta/commit endpoint instead");
//    }
//
//    /**
//     * 兼容性旧接口 - 打开文件
//     */
//    @RequestMapping("/open")
//    public ApiResponse<Map<String, Object>> open(@RequestHeader(required = false) String fileSystemName, @RequestParam String path) {
//        // 构造请求对象并调用新接口实现
//        OpenRequest request = OpenRequest.builder().path(path).mode("READ").build();
//        return open(request);
//    }
//
//    /**
//     * 关闭服务器接口（用于测试）
//     * 调用此接口将导致服务器进程退出
//     */
//    @RequestMapping("/shutdown")
//    public void shutdownServer() {
//        // 记录警告日志并退出进程
//        log.warn("Shutdown requested");
//        System.exit(-1);
//    }
}
